#!/usr/bin/python3

# Authors:
#     Dinesh Prasanth M K <dmoluguw@redhat.com>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the Lesser GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
#  along with this program; if not, write to the Free Software Foundation,
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
#
# Copyright (C) 2018 Red Hat, Inc.
# All rights reserved.


"""
Script that prompts user for password during server startup
and store them on user's keyring
"""

import getopt
import logging
import os
import subprocess
import sys

import pki.server
import pki.server.instance

from pki.keyring import Keyring

logger = logging.getLogger(__name__)

logging.basicConfig(format='%(levelname)s: %(message)s')

tags = set()

# Create a instance of Keyring
keyring = Keyring()


def split_entries(entry):
    return entry.split(',')


def print_help():
    print('Usage: pki-server-nuxwdog [OPTIONS]')
    print()
    print('      --clear                Clear values stored in keyring.')
    print('  -v, --verbose              Run in verbose mode.')
    print('      --debug                Run in debug mode.')
    print('      --help                 Show help message.')
    print()


try:
    opts, _ = getopt.gnu_getopt(sys.argv, 'v', [
        'clear', 'verbose', 'debug', 'help'])

except getopt.GetoptError as e:
    logger.error(e)
    print_help()
    sys.exit(1)

for o, a in opts:

    if o == '--clear':
        keyring.clear_keyring()
        sys.exit()

    elif o in ('-v', '--verbose'):
        logging.getLogger().setLevel(logging.INFO)

    elif o == '--debug':
        logging.getLogger().setLevel(logging.DEBUG)

    elif o == '--help':
        print_help()
        sys.exit()

    else:
        logger.error('option %s not recognized', o)
        print_help()
        sys.exit(1)

# 1. Get <instance> name from env variable NAME set in systemd unit file
instance_name = os.getenv('NAME', 'pki-tomcat')

# 2. Gather list of passwords required
# cms.tokenList, cms.passwordList --> For each subsystem in the <instance>

# Load the instance
instance = pki.server.instance.PKIInstance(instance_name)
instance.load()

subsystems = instance.get_subsystems()

tags.add('internal')

for subsystem in subsystems:
    if 'cms.passwordlist' in subsystem.config:
        password_list = split_entries(subsystem.config['cms.passwordlist'])
        tags.update(password_list)

    if 'cms.tokenList' in subsystem.config:
        token_list = split_entries(subsystem.config['cms.tokenList'])

        # HSM token requires a prefix 'hardware-'
        for token in token_list:
            tags.add('hardware-' + token)

# 3a. Search for password in keyring
# 3b. If not found, ask admin for password
# 3c. Store password into keyring

for tag in sorted(iter(tags)):

    key_name = instance_name + '/' + tag
    logger.info('Searching for %s in keyring', key_name)

    key_id = keyring.get_key_id(key_name)
    logger.debug('Key ID: %s', key_id)

    if key_id is not None:
        # password exists in keyring
        continue

    # ask admin for password

    if tag.startswith('hardware-'):
        prompt_tag = tag[9:]
    else:
        prompt_tag = tag

    prompt = '[' + instance_name + '] Please provide the password for ' + prompt_tag + ':'
    cmd_ask_password = ['systemd-ask-password', prompt]
    entered_pass = subprocess.check_output(cmd_ask_password)

    logger.info('Storing %s into keyring', key_name)
    keyring.put_password(key_name=key_name, password=entered_pass)

# 4. Put this script to sleep in background to keep the keyring fd open until main program starts
# due to systemd bug #1668954
subprocess.Popen(['/usr/bin/sleep', '10'])
